﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using ITAP.Core.Modelling;


namespace ITAP.ContourBuilder.Components
{
    public static class ContourComponentExtension
    {
        private static Random randomProvider = new Random();

        public static void AddInnerComponent(this IContourComponent component, IContourComponent innerComponent)
        {
            lock (component.InnerComponents)
            {
                ICollection<IContourComponent> innerComponents = component.InnerComponents as ICollection<IContourComponent>;
                if (innerComponents == null)
                    throw new ContourBuilderException("Компонент " + component.GetType().ToString() + " не поддерживает добавление внутренних компонент.");

                innerComponents.Add(innerComponent);
                innerComponent.Parent = component;
                if (innerComponent.SerialNumber == 0)
                    innerComponent.SerialNumber = randomProvider.Next(1, int.MaxValue);
            }
        }

        public static bool RemoveInnerComponent(this IContourComponent component, IContourComponent innerComponent)
        {
            lock (component.InnerComponents)
            {
                ICollection<IContourComponent> innerComponents = component.InnerComponents as ICollection<IContourComponent>;
                if (innerComponents == null)
                    throw new ContourBuilderException("Компонент " + component.GetType().ToString() + " не поддерживает удаление внутренних компонент.");

                if (innerComponents.Remove(innerComponent))
                {
                    innerComponent.Parent = null;
                    innerComponent.RemoveAllInnerComponents();


                    List<IContourComponent> componentsToDisconnect = new List<IContourComponent>();
                    foreach (IContourComponent connectedComponent in innerComponent.ConnectedComponents)
                    {
                        componentsToDisconnect.Add(connectedComponent);
                    }
                    foreach (IContourComponent connectedComponent in componentsToDisconnect)
                    {
                        ContourConnectionProvider.Disconnect(innerComponent, connectedComponent);
                        connectedComponent.ComponentsInTolerance.Clear();
                    }
                    innerComponent = null;
                    return true;
                }
                else
                    return false;
            }
        }

        public static void DisconnectFromAll(this IContourComponent component)
        {
            List<IContourComponent> componentsToDisconnect = new List<IContourComponent>();
            foreach (IContourComponent connectedComponent in component.ConnectedComponents)
            {
                componentsToDisconnect.Add(connectedComponent);
            }
            foreach (IContourComponent connectedComponent in componentsToDisconnect)
            {
                ContourConnectionProvider.Disconnect(component, connectedComponent);
                //connectedComponent.ComponentsInTolerance.Clear();
            }
        }

        //public static RectangleF GetBoundingBox(this IContourComponent component)
        //{
        //    return component.Primitive.BoundingBox;            
        //}

        public static ContourContainer GetRootContainer(this IContourComponent component)
        {
            IContourComponent parent = null;
            while (!(parent is ContourContainer))
            {
                parent = component.Parent;
                component = parent;
            }

            return parent as ContourContainer;
        }

        public static ContourModel GetRootModel(this IContourComponent component)
        {
            if (component is ContourContainer)
                return null;

            if (component is ContourModel)
                return component as ContourModel;

            IContourComponent parent = null;
            while (!(parent is ContourModel))
            {
                parent = component.Parent;
                component = parent;
            }

            return parent as ContourModel;
        }

        public static IEnumerable<IContourComponent> GetAllInnerComponents(this IContourComponent component)
        {

            // TODO: ПРОТЕСТИРОВАТЬ ПОЛУЧЕНИЕ ВСЕХ ВНУТРЕННИХ КОМПОНЕНТ.
            List<IContourComponent> allInnerComponents = new List<IContourComponent>();
            allInnerComponents.AddRange(component.InnerComponents);
            foreach (IContourComponent innerComponent in component.InnerComponents)
                allInnerComponents.AddRange(innerComponent.GetAllInnerComponents());

            return allInnerComponents;
        }

        public static void RemoveAllInnerComponents(this IContourComponent component)
        {
            List<IContourComponent> componentsToRemove = new List<IContourComponent>();

            foreach (IContourComponent innerComponent in component.InnerComponents)
            {
                innerComponent.RemoveAllInnerComponents();
                componentsToRemove.Add(innerComponent);
            }

            foreach (IContourComponent innerComponent in componentsToRemove)
            {
                component.RemoveInnerComponent(innerComponent);
            }
        }

        public static void DeselectAll(this IContourComponent component)
        {
            IEnumerable<IContourComponent> allComponents = component.GetAllInnerComponents();
            foreach (IContourComponent innerComponent in allComponents)
                innerComponent.Selected = false;
            component.GetRootContainer().SelectedComponentsStack.Clear();
        }

        public static void SelectAll(this IContourComponent component)
        {
            IEnumerable<IContourComponent> allComponents = component.GetAllInnerComponents();
            List<IContourComponent> selectedStack = component.GetRootContainer().SelectedComponentsStack;
            selectedStack.Clear();

            foreach (IContourComponent innerComponent in allComponents)
            {
                innerComponent.Selected = true;
                if (innerComponent.Selected)
                    selectedStack.Add(innerComponent);
            }
        }

        public static IEnumerable<IContourComponent> GetAllInnerComponentsByPoint(this IContourComponent component, ModelPoint point, double tolerance)
        {
            List<IContourComponent> components = new List<IContourComponent>();
            IEnumerable<IContourComponent> allComponents = component.GetAllInnerComponents();
            foreach (IContourComponent innerComponent in allComponents)
                if (innerComponent.IsInTolerance(point, tolerance))
                    components.Add(innerComponent);

            return components;

        }
    }
}
